<?php

/**
 * @copyright Michiel Hakvoort 2010
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD
 * @package mangrove
 * @subpackage grove
 * @filesource
 */

/*
 * Copyright (c) 2010 Michiel Hakvoort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

namespace mg;

/**
 * Viewable indicates an object has it's own, possibly distinct, {@link \mg\View View}.
 */
interface Viewable {

    /**
     *
     * @return \mg\View
     */
    public function getView();

}



/**
 * A View provides a certain view towards an object
 */
interface View {

    /**
     * In order to render an object it must be written as its string representation into a buffer.
     * The way an object get represented as a string is the responsibility of the View.
     *
     * @param mixed $object The object to write
     * @param \mg\Buffer $targetBuffer The target buffer to write the object into
     *
     */
    public function write($object, Buffer $targetBuffer);
}

/**
 * Adapter view implementation, do noop
 */
class ViewAdapter implements View {

    public function write($object, Buffer $targetBuffer) {

    }

}

/**
 *
 * @author Michiel Hakvoort
 */
interface Buffer {

    /**
     * Write a string into the buffer.
     *
     * @param string $text
     */
    public function write($text);

    /**
     * Check whether the Buffer is actually a proxy to php://output. By allowing
     * a Buffer to identify itself as php://output it is possible to optimize buffer
     * writes. The optimization should be a responsibility of {@link \mg\View View}
     *
     * @return true If a write to the Buffer results in writing to php://output.
     */
    public function isOutputBuffer();

}

/**
 * A simple Buffer which delegates to php://output.
 *
 * @author Michiel Hakvoort
 *
 */
class OutputBuffer implements Buffer {

    public function isOutputBuffer() {
        return true;
    }

    public function write($text) {
        echo $text;
    }
}

/**
 * A simple Buffer which caches everything that is written to it.
 *
 * @author Michiel Hakvoort
 *
 */
class CaptureBuffer implements Buffer {

    private $buffer = null;

    public function __construct() {
        $this->buffer = '';
    }

    public function isOutputBuffer() {
        return false;
    }

    public function write($text) {
        $this->buffer .= $text;
    }

    /**
     * Get the contents of the CaptureBuffer.
     *
     * @return string
     */
    public function getContent() {
        return $this->buffer;
    }

    /**
     * Clear the contents of the CaptureBuffer.
     */
    public function clear() {
        $this->buffer = '';
    }
}

/**
 * The ViewProvider is responsible for creating {@link \mg\View Views} for objects
 * which by themselves cannot deliver a {@link \mg\View View} (i.e. object which do not implement {@link \mg\Viewable}).
 *
 * @author Michiel Hakvoort
 *
 */
interface ViewProvider {

    /**
     * Create a {@link \mg\View} for an object
     *
     * @param mixed $object
     * @return \mg\View
     */
    public function createView($object);

}

/**
 * The DefaultViewProvider creates a noop {@link \mg\View} for every object.
 *
 * @author Michiel Hakvoort
 *
 */
class DefaultViewProvider implements ViewProvider {

    private $defaultView = null;

    public function __construct() {
        $this->defaultView = new ViewAdapter();
    }

    public function createView($object) {
        return $this->defaultView;
    }

}
